﻿using CommandSystem.Commands.RemoteAdmin.Broadcasts;
using Exiled.API.Enums;
using Exiled.API.Features;
using Exiled.API.Features.Pools;
using HarmonyLib;
using MEC;
using PlayerRoles;
using RemoteAdmin;
using RgCore.API;
using RgCore.Commands;
using RgCore.Events;
using RgCore.GameData;
using RgCore.GameModes;
using RgCore.Menu;
using RgCore.Misc;
using RgCore.Modules;
using RgCore.PlayerHud;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using RgCore.CustomSide;
using UnityEngine;
using Log = Exiled.API.Features.Log;

namespace RgCore
{
    public sealed class DatabaseConfig
    {
        public string IpAddress { get; set; } = "localhost";
        public uint Port { get; set; } = 3306;
        public string Username { get; set; } = "root";
        public string Password { get; set; } = "123456";
        public string Database { get; set; } = "mysql";
        public string PlayerTable { get; set; } = "cdcp_player_data_new";
    }

    public class PluginConfig : Exiled.API.Interfaces.IConfig
    {
        [Description("启动核心插件")]
        public bool IsEnabled { get; set; } = false;

        public bool Debug { get; set; } = false;

        [Description("安全模式，开启后不加载任何集成插件")]
        public bool SafeMode { get; set; } = true;

        [Description("数据库")]
        public DatabaseConfig Database { get; set; } = new DatabaseConfig();

        [Description("角色的默认物品")]
        public Dictionary<RoleTypeId, List<ItemType>> RoleDefaultItems { get; set; } = new Dictionary<RoleTypeId, List<ItemType>>
        {
            {
                RoleTypeId.FacilityGuard, new List<ItemType>
            {
                ItemType.GunCrossvec, ItemType.GrenadeHE, ItemType.KeycardGuard, ItemType.Radio, ItemType.Adrenaline, ItemType.Medkit, ItemType.ArmorLight,
            }
            },
            {
                RoleTypeId.Scientist, new List<ItemType>
            {
                ItemType.KeycardScientist,  ItemType.Medkit, ItemType.Adrenaline,
            }
            },
        };

        [Description("SCP受伤倍数（用于平衡）")]
        public float ScpDealtDamageMultiplier { get; set; } = 1f;

        [Description("激励模式。开启后，会对一部分非必要操作进行奖励（用于促进某种玩家行为，此功能通常用于无规则服务器）")]
        public bool InspirationMode { get; set; } = false;

        [Description("启动游戏模式")]
        public bool GameModeEnabled { get; set; } = false;
        [Description("强制关闭分数（无视游戏模式设定）")]
        public bool ScoreForceDisabled { get; set; } = false;
        [Description("禁用物品限制")]
        public bool InventoryLimiterDisabled { get; set; } = false;

        [Description("系统核弹时间（分钟）")]
        public int SystemWarheadMinute { get; set; } = 25;

        [Description("角色的默认子弹")]
        public Dictionary<RoleTypeId, Dictionary<ItemType, ushort>> RoleDefaultAmmo { get; set; } = new Dictionary<RoleTypeId, Dictionary<ItemType, ushort>>
        {
            {
                RoleTypeId.FacilityGuard, new Dictionary<ItemType, ushort>
                {
                    { ItemType.Ammo9x19, 180 },
                }
            },
        };

        [Description("白名单模式，开启后仅加载指定\"文件名\"的插件")]
        public bool WhitelistMode { get; set; } = false;

        [Description("禁用的插件列表，如果Whitelist_Mode为true则此选项为白名单列表")]
        public List<string> PluginNameList { get; set; } = new List<string>();
    }

    public class RgCore : Plugin<PluginConfig>
    {
        public override string Prefix => "rg";
        public static RgCore instance = null;
        public static event Action StartingRound;
        public static event Action RoundStarted;
        public static void Starting() => StartingRound?.Invoke();
        public static void StartRound() => RoundStarted?.Invoke();

        public static bool ForceEnd = false;
        private static CoroutineHandle _task = default;

        public static Harmony Harmony { get; private set; } = null;

        public override void OnEnabled()
        {
            base.OnEnabled();
            instance = this;
            Database.DatabaseController.Init();
            EventProcessor.Start();
            PlayerHud.PlayerHud.SetEnabled();
            GameplayData.SetEnabled();
            Exiled.Events.Handlers.Player.Verified += Player_Verified;
            Exiled.Events.Handlers.Server.EndingRound += Server_EndingRound;
            Exiled.Events.Handlers.Server.RestartingRound += Server_RestartingRound;
            Harmony = new Harmony("rgcore");
            Harmony.PatchAll();
            var handler = CommandProcessor.RemoteAdminCommandHandler;
            handler.UnregisterCommand(handler.AllCommands.FirstOrDefault(p => p is BroadcastCommand));
            handler.UnregisterCommand(handler.AllCommands.FirstOrDefault(p => p is PlayerBroadcastCommand));
            handler.RegisterCommand(new AdminBroadcastCommand());
            handler.RegisterCommand(new PrivateChatCommand());
            AllEventsInvoker.RegisterAllEvent();
            ScoreMvpHandler.RegisterEvents(true);
            if (!RgCore.instance.Config.InventoryLimiterDisabled)
            {

            InventoryLimiter.SetEnabled();
            }
            MenuInterface.SetEnabled();
            if (!Config.SafeMode)
            {
                ModuleManager.LoadPlugins();
            }
            else
                Log.Warn("安全模式已开启，不加载任何集成插件");
            GameMode.Active(Config.GameModeEnabled && !Config.SafeMode);
        }
        private void Server_RestartingRound()
        {
            SideManager.CustomedSide.Clear();
        }
        private void Player_Verified(Exiled.Events.EventArgs.Player.VerifiedEventArgs ev)
        {
            Dictionary<KeyCode, string> bindings = new Dictionary<KeyCode, string>()
            {
                {KeyCode.F9, ".v ty"},
                {KeyCode.F10, ".v fd" }
            };
            foreach (var bind in bindings)
            {
                ev.Player.GameObject.GetComponent<CharacterClassManager>()
                    .TargetChangeCmdBinding(bind.Key, bind.Value);
            }
        }
        private static async void SaveData(string[] content)
        {
            await Task.Run(delegate ()
            {
                Directory.CreateDirectory(Path.Combine(Paths.Exiled, "WinningLogs"));
                var path = Path.Combine(Paths.Exiled, "WinningLogs", $"{DateTime.Now:yyyy-MM-dd HH-mm-ss} 回合判定.txt");
                File.WriteAllLines(path, content);
            });
        }
        private static void Server_EndingRound(Exiled.Events.EventArgs.Server.EndingRoundEventArgs ev)
        {
            #region 前置
            var alive_players = ListPool<Player>.Pool.Get(Player.List.Where(x => x.IsAlive));
            Dictionary<string, byte> alives = DictionaryPool<string, byte>.Pool.Get();
            List<string> dataoutput = ListPool<string>.Pool.Get();
            dataoutput.Add("-------------回合结束日志----------------");
            byte total_no_neutral = 0;
            byte total = 0;
            for (int i = 0; i < SideManager.Sides.Count; i++)
            {
                var side = SideManager.Sides[i];
                byte count = (byte)alive_players.Count(x => x.GetSide() == side);
                alives.Add(side.Id, count);
                total += count;
                if (side != Side.None)
                    total_no_neutral += count;
            }
            ListPool<Player>.Pool.Return(alive_players);
            byte classd = 0;
            byte scientist = 0;
            byte chaos = 0;
            byte mtf = 0;
            byte scp = 0;
            byte zombie = 0;
            byte chaosTargetCount = (byte)RoundSummary.singleton.ChaosTargetCount;
            dataoutput.Add(">>存活玩家列表<<");
            foreach (Player player in Player.List)
            {
                if (!player.IsAlive)
                    continue;
                var side = player.GetSide();
                dataoutput.Add($"[] {player.Nickname} : {player.Role.Type} ({side.Id})【{side.SideName}】");
                switch (side.Id)
                {
                    case nameof(Side.Mtf):
                        if (player.Role.Team == Team.Scientists)
                        {
                            scientist++; 
                            dataoutput[dataoutput.Count - 1] += " <*>";
                        }
                        else
                            mtf++;
                        continue;
                    case nameof(Side.Scp):
                        if (player.Role.Type != RoleTypeId.Scp0492)
                            scp++;
                        else
                            zombie++;
                        continue;
                    case nameof(Side.ChaosInsurgency):
                        if (player.Role.Team == Team.ClassD)
                        {
                            classd++;
                            dataoutput[dataoutput.Count - 1] += " <*>";
                        }
                        else
                            chaos++;
                        continue;
                }
            }
            dataoutput.Add("====================");
            dataoutput.Add("MTF 剩余人数：" + mtf);
            dataoutput.Add("CI 剩余人数：" + chaos);
            dataoutput.Add("CI 待击杀数：" + chaosTargetCount);
            dataoutput.Add("D级人员 剩余人数：" + classd);
            dataoutput.Add("科学家 剩余人数：" + scientist);
            dataoutput.Add($"SCP 剩余人数：{scp}（僵尸：{zombie}）");
            ev.ClassList = new RoundSummary.SumInfo_ClassList()
            {
                mtf_and_guards = mtf,
                chaos_insurgents = chaos,
                class_ds = classd,
                scientists = scientist,
                scps_except_zombies = scp,
                zombies = zombie,
                warhead_kills = AlphaWarheadController.Detonated ? AlphaWarheadController.Singleton.WarheadKills : -1
            };
            #endregion
            ev.LeadingTeam = LeadingTeam.Draw;
            if (ForceEnd)
            {
                dataoutput.Add($"【回合强制结束】");
                ForceEnd = false;
                HudHandler.SendFormattedMsg("roundsummary", "<color=#1E90FF>回合结束</color>", "回合已被强制结束", 15, MsgType.Announcement, ScreenLocation.CenterTop, true, Player.List.ToArray());
                ev.IsRoundEnded = true;
                ev.IsAllowed = true;
                SaveData(ListPool<string>.Pool.ToArrayReturn(dataoutput));
                return;
            }
            if (total_no_neutral == 0)
            {
                dataoutput.Add($"【无其他非中立玩家】");
                HudHandler.SendFormattedMsg("roundsummary", "<color=#1E90FF>回合结束</color>", "僵局.... 所有生命体已经消亡...", 15, MsgType.Announcement, ScreenLocation.CenterTop, true, Player.List.ToArray());
                ev.IsRoundEnded = true;
                ev.IsAllowed = true;
                SaveData(ListPool<string>.Pool.ToArrayReturn(dataoutput));
                return;
            }
            dataoutput.Add($"总共存活人数：{total}（中立：{total - total_no_neutral}）");
            RoundInfo info = new RoundInfo
            {
                SideAlives = alives,
                AlivesWithoutNeutral = total_no_neutral,
                Chaos_Alives = chaos,
                ClassD_Alives = classd,
                Mtf_Alives = mtf,
                Scientist_Alives = scientist,
                Scp_Alives = scp,
                TotalAlives = total,
                Zombies = zombie,
                ChaosTargetCount = chaosTargetCount
            };
            Dictionary<CustomSide.CustomSide, bool?> result = DictionaryPool<CustomSide.CustomSide, bool?>.Pool.Get();
            byte TRUE = 0;
            byte FALSE = 0;
            for (int i = 0; i < SideManager.Sides.Count; i++)
            {
                var side = SideManager.Sides[i];
                if (side.WinningCondition == null)
                {
                    dataoutput.Add($"{side.SideName}（{side.Id}）无胜利条件。");
                    continue;
                }
                var r = side.WinningCondition(info);
                result.Add(side, r);
                switch (r)
                {
                    case true:
                        TRUE++; dataoutput.Add($"★ {side.SideName}（{side.Id}）达成胜利条件！"); break;
                    case false:
                        FALSE++; dataoutput.Add($"✔ {side.SideName}（{side.Id}）完成了目标！"); break;
                    case null:
                        dataoutput.Add($"✘ {side.SideName}（{side.Id}）未达成目标。"); break;
                }
            }
            DictionaryPool<string, byte>.Pool.Return(alives);
            if (TRUE > 0)
            {
                string text = "[ ";
                foreach (var winner in result.Where(x => x.Value == true))
                {
                    text += winner.Key.FormattedName + " ";
                    if (winner.Key == Side.Mtf)
                        ev.LeadingTeam = LeadingTeam.FacilityForces;
                    if (winner.Key == Side.ChaosInsurgency)
                        ev.LeadingTeam = LeadingTeam.ChaosInsurgency;
                    if (winner.Key == Side.Scp)
                        ev.LeadingTeam = LeadingTeam.Anomalies;
                }
                text += "] 赢得了本场游戏的胜利！";
                HudHandler.SendFormattedMsg("roundsummary", "<color=#1E90FF>回合结束</color>", text, 15, MsgType.Announcement, ScreenLocation.CenterTop, true, Player.List.ToArray());
                DictionaryPool<CustomSide.CustomSide, bool?>.Pool.Return(result);
                ev.IsRoundEnded = true;
                ev.IsAllowed = true;
                SaveData(ListPool<string>.Pool.ToArrayReturn(dataoutput));
                return;
            }
            if (FALSE > 0)
            {
                string text = "僵局...但 [ ";
                foreach (var winner in result.Where(x => x.Value == false))
                    text += winner.Key.FormattedName + " ";
                text += "] 完成了任务目标";
                HudHandler.SendFormattedMsg("roundsummary", "<color=#1E90FF>回合结束</color>", text, 15, MsgType.Announcement, ScreenLocation.CenterTop, true, Player.List.ToArray());
                DictionaryPool<CustomSide.CustomSide, bool?>.Pool.Return(result);
                ev.IsRoundEnded = true;
                ev.IsAllowed = true;
                SaveData(ListPool<string>.Pool.ToArrayReturn(dataoutput));
                return;
            }
            ListPool<string>.Pool.Return(dataoutput);
            DictionaryPool<CustomSide.CustomSide, bool?>.Pool.Return(result);
            ev.IsAllowed = false;
            return;
        }
    }
}